package com.example.module.webview

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.invoke
import kotlinx.coroutines.launch


@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebView(state: WebViewState) {

    var webView by remember {
        mutableStateOf<WebView?>(null)
    }

    //webView变化或state变化时重新订阅流数据
    LaunchedEffect(webView, state) {
        with(state) {
            //订阅流
            webView?.handleEvent()
        }
    }
    // WebView 组件
    AndroidView(factory = {
        WebView(it).apply {
            webChromeClient = object : WebChromeClient() {
                override fun onReceivedTitle(view: WebView?, title: String?) {
                    super.onReceivedTitle(view, title)
                    state.pageTitle = title
                }
            }
            webViewClient = object : WebViewClient() {
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    super.onPageStarted(view, url, favicon)
                    state.pageTitle = null
                }
            }
            settings.javaScriptEnabled = true
        }.also {
            webView = it
        }
    }, update = {
        when (val content = state.content) {
            is WebContent.Url -> {
                val url = content.url
                if (url.isNotEmpty() && url != it.url) {
                    it.loadUrl(content.url)
                }
            }

            is WebContent.Data -> {
                it.loadDataWithBaseURL(content.baseUrl, content.data, null, "utf-8", "")
            }
        }
    }, modifier = Modifier.fillMaxSize()
    )
}

sealed class WebContent {
    data class Url(val url: String) : WebContent()
    data class Data(val data: String, val baseUrl: String? = "") : WebContent()
}

class WebViewState(private val coroutineScope: CoroutineScope, webContent: WebContent) {
    //网页内容：url 或者 data（html内容)
    var content by mutableStateOf(webContent)

    var pageTitle: String? by mutableStateOf(null)
        internal set

    //事件类型
    private enum class EventType {
        EVALUATE_JAVASCRIPT  //执行js方法
    }

    //共享流的数据类型
    private class Event(val type: EventType, val args: String, val callback: ((String) -> Unit)?)

    //共享流
    private val events: MutableSharedFlow<Event> = MutableSharedFlow()

    suspend fun WebView.handleEvent(): Unit = (Dispatchers.Main) {
        events.collect { event ->
            when (event.type) {
                EventType.EVALUATE_JAVASCRIPT -> evaluateJavascript(event.args, event.callback)
            }
        }
    }

    //执行js方法
    fun evaluateJavascript(script: String, resultCallback: ((String) -> Unit)? = {}) {
        val event = Event(EventType.EVALUATE_JAVASCRIPT, script, resultCallback)
        coroutineScope.launch {
            events.emit(event)//推送流
        }
    }
}

@Composable
fun rememberWebViewState(coroutineScope: CoroutineScope = rememberCoroutineScope(), url: String) =
    remember(key1 = url) {
        WebViewState(coroutineScope, WebContent.Url(url))
    }

@Composable
fun rememberWebViewState(
    coroutineScope: CoroutineScope = rememberCoroutineScope(), data: String, baseUrl: String? = ""
) = remember(key1 = data, key2 = baseUrl) {
    WebViewState(coroutineScope, WebContent.Data(data, baseUrl))
}

@Preview
@Composable
fun WebViewPreview() {
    WebView(rememberWebViewState(data = "<h1>Header<h1/>"))
}

